home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Best of Shareware
/
Best of PC Windows Shareware 1.0 - Wayzata Technology (7111) (1993).iso
/
mac
/
ZIPPED
/
DOS
/
GRAPHICS
/
RAYSH386.ZIP
/
SRC
/
CYLINDER.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-07-18
|
5KB
|
241 lines
/*
* cylinder.c
*
* Copyright (C) 1989, 1991, Craig E. Kolb
* All rights reserved.
*
* This software may be freely copied, modified, and redistributed
* provided that this copyright notice is preserved on all copies.
*
* You may not distribute this software, in whole or in part, as part of
* any commercial product without the express consent of the authors.
*
* There is no warranty or other guarantee of fitness of this software
* for any purpose. It is provided solely "as is".
*
* $Id: cylinder.c,v 4.0 91/07/17 14:37:12 kolb Exp Locker: kolb $
*
* $Log: cylinder.c,v $
* Revision 4.0 91/07/17 14:37:12 kolb
* Initial version.
*
*/
#include "geom.h"
#include "cylinder.h"
static Methods *iCylinderMethods = NULL;
static char cylName[] = "cylinder";
unsigned long CylTests, CylHits;
Cylinder *
CylinderCreate(r, bot, top)
Float r;
Vector *bot, *top;
{
Cylinder *cyl;
Float len;
Vector axis;
if (r <= 0.) {
RLerror(RL_WARN, "Invalid cylinder radius.\n");
return (Cylinder*)NULL;
}
VecSub(*top, *bot, &axis);
len = VecNormalize(&axis);
if (len < EPSILON) {
RLerror(RL_WARN, "Degenerate cylinder.\n");
return (Cylinder *)NULL;
}
cyl = (Cylinder *)share_malloc(sizeof(Cylinder));
CoordSysTransform(bot, &axis, r, len, &cyl->trans);
return cyl;
}
Methods *
CylinderMethods()
{
if (iCylinderMethods == (Methods *)NULL) {
iCylinderMethods = MethodsCreate();
iCylinderMethods->name = CylinderName;
iCylinderMethods->create = (GeomCreateFunc *)CylinderCreate;
iCylinderMethods->methods = CylinderMethods;
iCylinderMethods->intersect = CylinderIntersect;
iCylinderMethods->normal = CylinderNormal;
iCylinderMethods->uv = CylinderUV;
iCylinderMethods->bounds = CylinderBounds;
iCylinderMethods->stats = CylinderStats;
iCylinderMethods->checkbounds = TRUE;
iCylinderMethods->closed = FALSE;
}
return iCylinderMethods;
}
/*
* Ray-cylinder intersection test.
*/
int
CylinderIntersect(cyl, ray, mindist, maxdist)
Cylinder *cyl;
Ray *ray;
Float mindist, *maxdist;
{
Float t1, t2, a, b, c, zpos1, zpos2, disc;
Float distfact;
Ray newray;
Vector nray, npos;
Float nmin;
CylTests++;
/*
* Transform ray into canonical cylinder space.
*/
newray = *ray;
distfact = RayTransform(&newray, &cyl->trans.itrans);
nray = newray.dir;
npos = newray.pos;
nmin = mindist * distfact;
a = nray.x * nray.x + nray.y * nray.y;
if (a < EPSILON*EPSILON)
/* |nray.z| == 1. */
return FALSE;
b = nray.x * npos.x + nray.y * npos.y;
c = npos.x*npos.x + npos.y*npos.y - 1;
disc = b*b - a*c;
if(disc < 0.)
return FALSE;
disc = sqrt(disc);
t1 = (-b + disc) / a;
t2 = (-b - disc) / a;
if (t1 < nmin && t2 < nmin)
return FALSE;
zpos1 = npos.z + t1 * nray.z;
zpos2 = npos.z + t2 * nray.z;
if (t1 < nmin || zpos1 < 0. || zpos1 > 1.) {
if (t2 < nmin || zpos2 < 0. || zpos2 > 1.)
return FALSE;
else
t1 = t2 / distfact;
} else {
if (t2 < nmin || zpos2 < 0. || zpos2 > 1.)
t1 /= distfact;
else {
t1 = min(t1, t2) / distfact;
}
}
if (t1 < *maxdist) {
*maxdist = t1;
CylHits++;
return TRUE;
}
return FALSE;
}
int
CylinderNormal(cyl, pos, nrm, gnrm)
Cylinder *cyl;
Vector *pos, *nrm, *gnrm;
{
/*
* Transform position into cylinder space.
*/
*nrm = *pos;
PointTransform(nrm, &cyl->trans.itrans);
/*
* The normal is equal to the point of intersection in cylinder
* space, but with Z = 0.;
*/
nrm->z = 0.;
/*
* Tranform normal back to world space.
*/
NormalTransform(nrm, &cyl->trans.itrans);
*gnrm = *nrm;
return FALSE;
}
void
CylinderUV(cyl, pos, norm, uv, dpdu, dpdv)
Cylinder *cyl;
Vector *pos, *norm, *dpdu, *dpdv;
Vec2d *uv;
{
Vector npos;
npos = *pos;
PointTransform(&npos, &cyl->trans.itrans);
uv->v = npos.z;
/*
* Due to roundoff error, |npos.x| may be > 1.
*/
if (npos.x > 1.)
uv->u = 0.;
else if (npos.x < -1.)
uv->u = 0.5;
else
uv->u = acos(npos.x) / TWOPI;
if (npos.y < 0.)
uv->u = 1. - uv->u;
if (dpdu) {
dpdv->x = dpdv->y = 0.;
dpdv->z = 1.;
dpdu->x = -npos.y;
dpdu->y = npos.x;
dpdu->z = 0.;
VecTransform(dpdu, &cyl->trans.trans);
VecTransform(dpdv, &cyl->trans.trans);
(void)VecNormalize(dpdu);
(void)VecNormalize(dpdv);
}
}
void
CylinderBounds(cyl, bounds)
Cylinder *cyl;
Float bounds[2][3];
{
bounds[LOW][X] = bounds[LOW][Y] = -1;
bounds[HIGH][X] = bounds[HIGH][Y] = 1;
bounds[LOW][Z] = 0.;
bounds[HIGH][Z] = 1;
/*
* Transform bounding box to world space.
*/
BoundsTransform(&cyl->trans.trans, bounds);
}
char *
CylinderName()
{
return cylName;
}
void
CylinderStats(tests, hits)
unsigned long *tests, *hits;
{
*tests = CylTests;
*hits = CylHits;
}
void
CylinderMethodRegister(meth)
UserMethodType meth;
{
if (iCylinderMethods)
iCylinderMethods->user = meth;
}